﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Common.Utilities.DLR;

namespace Workflows.Components.ETL
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class DataCleaningInstruction:InstructionBase
    {
        #region src
        private List<DataCleaningRule> _DataCleaningRules;
        /// <summary></summary>
        public List<DataCleaningRule> DataCleaningRules
        {
            get
            {
                return this._DataCleaningRules;
            }
            set
            {
                this._DataCleaningRules = value;
            }
        }

        private DataPipeSourceType _SourceType;
        /// <summary></summary>
        public DataPipeSourceType SourceType
        {
            get
            {
                return this._SourceType;
            }
            set
            {
                this._SourceType = value;
            }
        }

        private DataProviderType _DbProvider;
        /// <summary></summary>
        public DataProviderType DbProvider
        {
            get
            {
                return this._DbProvider;
            }
            set
            {
                this._DbProvider = value;
            }
        }

        private string _ConnStr;
        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._ConnStr;
            }
            set
            {
                this._ConnStr = value;
            }
        }

        private string _SelectSql;
        /// <summary></summary>
        public string SelectSql
        {
            get
            {
                return this._SelectSql;
            }
            set
            {
                this._SelectSql = value;
            }
        }

        private string _GroupBy;
        /// <summary></summary>
        public string GroupBy
        {
            get
            {
                return this._GroupBy;
            }
            set
            {
                this._GroupBy = value;
            }
        }

        private string _SortBy;
        /// <summary></summary>
        public string SortBy
        {
            get
            {
                return this._SortBy;
            }
            set
            {
                this._SortBy = value;
            }
        }

        private string _TblName;
        /// <summary></summary>
        public string TblName
        {
            get
            {
                return this._TblName;
            }
            set
            {
                this._TblName = value;
            }
        }

        private string _RootFolderPath;
        /// <summary></summary>
        public string RootFolderPath
        {
            get
            {
                return this._RootFolderPath;
            }
            set
            {
                this._RootFolderPath = value;
            }
        }

        private string _FileFilter;
        /// <summary></summary>
        public string FileFilter
        {
            get
            {
                return this._FileFilter;
            }
            set
            {
                this._FileFilter = value;
            }
        }
        

        private SearchOption _FolderSearchOption;
        /// <summary></summary>
        public SearchOption FolderSearchOption
        {
            get
            {
                return this._FolderSearchOption;
            }
            set
            {
                this._FolderSearchOption = value;
            }
        }
        #endregion

        #region tgt
        /// <summary></summary>
        public DataPipeSerializationMethod SerializationMethod
        {
            get { return _SerializationMethod; }
            set { _SerializationMethod = value; }
        }
        /// <summary></summary>
        public string CustomTypeAssemblyPath
        {
            get { return _CustomTypeAssemblyPath; }
            set { _CustomTypeAssemblyPath = value; }
        }
        /// <summary></summary>
        public string CustomTypeName
        {
            get { return _CustomTypeName; }
            set { _CustomTypeName = value; }
        }
        /// <summary></summary>
        public DataProviderType TgtDbProvider
        {
            get { return _TgtDbProvider; }
            set { _TgtDbProvider = value; }
        }
        /// <summary></summary>
        public string TgtConnStr
        {
            get { return _TgtConnStr; }
            set { _TgtConnStr = value; }
        }
        /// <summary></summary>
        public string TgtFolderPath
        {
            get { return _TgtFolderPath; }
            set { _TgtFolderPath = value; }
        }
        /// <summary></summary>
        public string TgtFileNameFormat
        {
            get { return _TgtFileNameFormat; }
            set { _TgtFileNameFormat = value; }
        }
        #endregion

        #region fields for serialization
        private DataPipeSerializationMethod _SerializationMethod;
        private string _CustomTypeAssemblyPath;
        private string _CustomTypeName;
        private DataProviderType _TgtDbProvider;
        private string _TgtConnStr;
        private string _TgtFolderPath;
        private string _TgtFileNameFormat;
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        public DataCleaningInstruction():base(Guid.Empty,Guid.Empty)
        {
            this._DataCleaningRules = null;
            this._SourceType = DataPipeSourceType.FileProvider;
            this._DbProvider = DataProviderType.MSSQL;
            this._ConnStr = string.Empty;
            this._SelectSql = string.Empty;
            this._GroupBy = string.Empty;
            this._SortBy = string.Empty;
            this._TblName = string.Empty;
            this._RootFolderPath = string.Empty;
            this._FileFilter = string.Empty;
            this._FolderSearchOption = System.IO.SearchOption.TopDirectoryOnly;
            this._SerializationMethod = DataPipeSerializationMethod.SaveToDB;
            this._CustomTypeAssemblyPath = string.Empty;
            this._CustomTypeName = string.Empty;
            this._TgtDbProvider = DataProviderType.MSSQL;
            this._TgtConnStr = string.Empty;
            this._TgtFolderPath = string.Empty;
            this._TgtFileNameFormat = string.Empty;
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="componentID"></param>
        /// <param name="jobTicketID"></param>
        /// <param name="rules"></param>
        /// <param name="dataSrcType"></param>
        /// <param name="dbProvider"></param>
        /// <param name="connStr"></param>
        /// <param name="selectSql"></param>
        /// <param name="groupBy"></param>
        /// <param name="sortBy"></param>
        /// <param name="tblName"></param>
        /// <param name="rootFolderPath"></param>
        /// <param name="fileFilter"></param>
        /// <param name="searchOp"></param>
        /// <param name="serializationMethod"></param>
        /// <param name="cusomTypeAssemblyFilePath"></param>
        /// <param name="customTypeName"></param>
        /// <param name="tgtDbProvider"></param>
        /// <param name="tgtConnStr"></param>
        /// <param name="tgtFolderPath"></param>
        /// <param name="tgtFileNamePattern"></param>
        public DataCleaningInstruction(Guid componentID, Guid jobTicketID, 
            List<DataCleaningRule> rules, 
            DataPipeSourceType dataSrcType,
            DataProviderType dbProvider,
            string connStr,
            string selectSql,
            string groupBy,
            string sortBy,
            string tblName,
            string rootFolderPath,
            string fileFilter,
            SearchOption searchOp,
            DataPipeSerializationMethod serializationMethod,
            string cusomTypeAssemblyFilePath,
            string customTypeName,
            DataProviderType tgtDbProvider,
            string tgtConnStr,
            string tgtFolderPath,
            string tgtFileNamePattern
            ) 
            : base(componentID, jobTicketID)
        {
            this._DataCleaningRules = rules;
            this._SourceType = dataSrcType;
            this._DbProvider = dbProvider;
            this._ConnStr = connStr;
            this._SelectSql = selectSql;
            this._GroupBy = groupBy;
            this._SortBy = sortBy;
            this._TblName = tblName;
            this._RootFolderPath = rootFolderPath;
            this._FileFilter = fileFilter;
            this._FolderSearchOption = searchOp;
            this._SerializationMethod = serializationMethod;
            this._CustomTypeAssemblyPath = CustomTypeAssemblyPath;
            this._CustomTypeName = customTypeName;
            this._TgtDbProvider = tgtDbProvider;
            this._TgtConnStr = tgtConnStr;
            this._TgtFolderPath = tgtFolderPath;
            this._TgtFileNameFormat = tgtFileNamePattern;
        }
        #endregion

        /// <summary>serialize settings to xml</summary>
        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DataSourceType", ((int) this.SourceType).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DbProviderType", ((int) this.DbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnStr", this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SelectSql", this.SelectSql);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "GroupBy", this.GroupBy);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SortBy", this.SortBy);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TableName", this.TblName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "RootFolderPath", this.RootFolderPath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "FileFilter", this.FileFilter);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SearchOption", ((int) this.FolderSearchOption).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"SerializationMethod",((int)this.SerializationMethod).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"CustomTypeAssemblyFilePath",this.CustomTypeAssemblyPath);
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"CustomTypeName",this.CustomTypeName);
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"TgtDbProvider",((int)this.TgtDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"TgtConnStr",this.TgtConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"TgtFolderPath",this.TgtFolderPath);
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"TgtFileNamePattern",this.TgtFileNameFormat);

            if(this.DataCleaningRules !=null && this.DataCleaningRules.Count>0)
            {
                XmlNode ruleRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "DataCleaningRules");
                foreach(DataCleaningRule rule in this.DataCleaningRules)
                {
                    XmlNode ruleNode = XmlDataUtil.AddElement(ref xDoc, ruleRootNode, "DataCleaningRule");
                    XmlDataUtil.UpdateAttribute(ref xDoc,ruleNode,"DataCleaningRuleID",rule.DataCleaningRuleID.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "RuleName", rule.RuleName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "ExternalReferences",
                                                StringUtil.ToString(rule.ExternalReferences));
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "TypeNameToEvaluate", rule.ObjectTypeNameToEvaluate);
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "CodeSnippet", rule.CodeSnippet);
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "TrueAction", ((int) rule.TrueAction).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, ruleNode, "FalseAction", ((int) rule.FalseAction).ToString());
                }
            }
            
            return xNode;
        }

        /// <summary>
        /// instantiated from xml
        /// "&lt;Instructions&gt;&lt;Instruction&gt;&lt;/Instruction&gt;&lt;/Instruction&gt;", must
        /// instantiate from first child of root node
        /// </summary>
        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                DataCleaningInstruction instruction = new DataCleaningInstruction();
                instruction.OwnerComponentID = new Guid(XmlDataUtil.GetAttributeValue(xNode, "ComponentID", Guid.NewGuid().ToString()));
                instruction.OwnerWorkerInstanceID = new Guid(XmlDataUtil.GetAttributeValue(xNode, "WorkerID", Guid.NewGuid().ToString()));
                instruction.SubmitTime = DateTime.Parse(XmlDataUtil.GetAttributeValue(xNode, "SubmitTime", TimeUtil.DbMinTime.ToString()));
                instruction.StartTime = DateTime.Parse(XmlDataUtil.GetAttributeValue(xNode, "StartTime", TimeUtil.DbMinTime.ToString()));

                instruction.SourceType =
                    (DataPipeSourceType)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "DataSourceType",
                                                            ((int) DataPipeSourceType.FileProvider).ToString()));
                instruction.DbProvider =
                    (DataProviderType)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "DbProviderType",
                                                            ((int) DataProviderType.MSSQL).ToString()));
                instruction.ConnStr = XmlDataUtil.GetAttributeValue(xNode, "ConnStr", "");
                instruction.SelectSql = XmlDataUtil.GetAttributeValue(xNode, "SelectSql", "");
                instruction.GroupBy = XmlDataUtil.GetAttributeValue(xNode, "GroupBy", "");
                instruction.SortBy = XmlDataUtil.GetAttributeValue(xNode, "SortBy", "");
                instruction.TblName = XmlDataUtil.GetAttributeValue(xNode, "TableName", "");
                instruction.RootFolderPath = XmlDataUtil.GetAttributeValue(xNode, "TableName", "");
                instruction.FileFilter = XmlDataUtil.GetAttributeValue(xNode, "FileFilter", "");
                instruction.FolderSearchOption =
                    (SearchOption)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "SearchOption",
                                                            ((int) SearchOption.TopDirectoryOnly).ToString()));
                instruction.SerializationMethod =
                    (DataPipeSerializationMethod)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "SerializationMethod",
                                                            ((int) DataPipeSerializationMethod.SaveToDB).ToString()));
                instruction.CustomTypeAssemblyPath = XmlDataUtil.GetAttributeValue(xNode, "CustomAssemblyFilePath", "");
                instruction.CustomTypeName = XmlDataUtil.GetAttributeValue(xNode, "CustomTypeName", "");
                instruction.TgtDbProvider =
                    (DataProviderType)
                    int.Parse(XmlDataUtil.GetAttributeValue(xNode, "TgtDbProvider",
                                                            ((int) DataProviderType.MSSQL).ToString()));
                instruction.TgtConnStr = XmlDataUtil.GetAttributeValue(xNode, "TgtConnStr", "");
                instruction.TgtFolderPath = XmlDataUtil.GetAttributeValue(xNode, "TgtFolderPath", "");
                instruction.TgtFileNameFormat = XmlDataUtil.GetAttributeValue(xNode, "TgtFileNamePattern", "");

                instruction.DataCleaningRules = null;
                XmlNodeList ruleNodes = xNode.SelectNodes("//DataCleaningRule");
                if(ruleNodes !=null && ruleNodes.Count>0)
                {
                    instruction.DataCleaningRules=new List<DataCleaningRule>();
                    foreach(XmlNode ruleNode in ruleNodes)
                    {
                        DataCleaningRule rule=new DataCleaningRule();
                        rule.DataCleaningRuleID =
                            new Guid(XmlDataUtil.GetAttributeValue(ruleNode, "DataCleaningRuleID", Guid.Empty.ToString()));
                        rule.RuleName = XmlDataUtil.GetAttributeValue(ruleNode, "RuleName", string.Empty);
                        rule.ExternalReferences =
                            StringUtil.Split(XmlDataUtil.GetAttributeValue(ruleNode, "ExternalReferences", string.Empty));
                        rule.ObjectTypeNameToEvaluate = XmlDataUtil.GetAttributeValue(ruleNode, "TypeNameToEvaluate",
                                                                                      string.Empty);
                        rule.CodeSnippet = XmlDataUtil.GetAttributeValue(ruleNode, "CodeSnippet", string.Empty);
                        rule.TrueAction =
                            (DataFlowAction)
                            int.Parse(XmlDataUtil.GetAttributeValue(ruleNode, "TrueAction",
                                                                    ((int) DataFlowAction.MoveToNext).ToString()));
                        rule.FalseAction =
                            (DataFlowAction)
                            int.Parse(XmlDataUtil.GetAttributeValue(ruleNode, "FalseAction",
                                                                    ((int) DataFlowAction.BreakToEnd).ToString()));
                        instruction.DataCleaningRules.Add(rule);
                    }
                }

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate component: invalid type specified in xml node");
            }
        }
    }
}
